Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
56.52% covered (warning)
56.52%
13 / 23
CRAP
96.27% covered (success)
96.27%
1162 / 1207
PptCharts
0.00% covered (danger)
0.00%
0 / 1
56.52% covered (warning)
56.52%
13 / 23
215
96.27% covered (success)
96.27%
1162 / 1207
 render
0.00% covered (danger)
0.00%
0 / 1
5.02
90.91% covered (success)
90.91%
10 / 11
 writeChart
0.00% covered (danger)
0.00%
0 / 1
8.23
84.72% covered (warning)
84.72%
61 / 72
 writeSpreadsheet
0.00% covered (danger)
0.00%
0 / 1
7.04
90.32% covered (success)
90.32%
28 / 31
 writeElementWithValAttribute
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 writeSingleValueOrReference
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
16 / 16
 writeMultipleValuesOrReference
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
26 / 26
 writeTitle
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
48 / 48
 writePlotArea
100.00% covered (success)
100.00%
1 / 1
12
100.00% covered (success)
100.00%
28 / 28
 writeLegend
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
48 / 48
 writeLayout
0.00% covered (danger)
0.00%
0 / 1
5.27
77.78% covered (warning)
77.78%
21 / 27
 writeTypeArea
0.00% covered (danger)
0.00%
0 / 1
9.02
93.48% covered (success)
93.48%
43 / 46
 writeTypeBar
0.00% covered (danger)
0.00%
0 / 1
20.25
91.43% covered (success)
91.43%
96 / 105
 writeTypeBar3D
0.00% covered (danger)
0.00%
0 / 1
15
96.74% covered (success)
96.74%
89 / 92
 writeTypeDoughnut
0.00% covered (danger)
0.00%
0 / 1
20
95.29% covered (success)
95.29%
81 / 85
 writeTypePie
0.00% covered (danger)
0.00%
0 / 1
15.03
94.94% covered (success)
94.94%
75 / 79
 writeTypePie3D
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
76 / 76
 writeTypeLine
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
81 / 81
 writeTypeRadar
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
82 / 82
 writeTypeScatter
100.00% covered (success)
100.00%
1 / 1
16
100.00% covered (success)
100.00%
85 / 85
 writeChartRelationships
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
8 / 8
 writeSeriesMarker
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
19 / 19
 writeAxis
0.00% covered (danger)
0.00%
0 / 1
19
99.25% covered (success)
99.25%
133 / 134
 writeAxisGridlines
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
1<?php
2
3namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
4
5use PhpOffice\Common\Adapter\Zip\ZipInterface;
6use PhpOffice\Common\Drawing as CommonDrawing;
7use PhpOffice\Common\XMLWriter;
8use PhpOffice\PhpPresentation\PhpPresentation;
9use PhpOffice\PhpPresentation\Shape\Chart;
10use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
11use PhpOffice\PhpPresentation\Shape\Chart\Legend;
12use PhpOffice\PhpPresentation\Shape\Chart\PlotArea;
13use PhpOffice\PhpPresentation\Shape\Chart\Title;
14use PhpOffice\PhpPresentation\Shape\Chart\Type\Area;
15use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;
16use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D;
17use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut;
18use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
19use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
20use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D;
21use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
22use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
23use PhpOffice\PhpPresentation\Style\Border;
24use PhpOffice\PhpPresentation\Style\Fill;
25use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
26use PhpOffice\PhpSpreadsheet\IOFactory;
27use PhpOffice\PhpSpreadsheet\Spreadsheet;
28
29class PptCharts extends AbstractDecoratorWriter
30{
31    /**
32     * @throws \Exception
33     */
34    public function render(): ZipInterface
35    {
36        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
37            $shape = $this->getDrawingHashTable()->getByIndex($i);
38            if ($shape instanceof Chart) {
39                $this->getZip()->addFromString('ppt/charts/' . $shape->getIndexedFilename(), $this->writeChart($shape));
40
41                if ($shape->hasIncludedSpreadsheet()) {
42                    $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape));
43                    $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet');
44                    $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx'));
45
46                    // remove temp file
47                    if (false === @unlink($pFilename)) {
48                        throw new \Exception('The file ' . $pFilename . ' could not removed.');
49                    }
50                }
51            }
52        }
53
54        return $this->getZip();
55    }
56
57    /**
58     * Write chart to XML format.
59     *
60     * @return string XML Output
61     *
62     * @throws \Exception
63     */
64    public function writeChart(Chart $chart): string
65    {
66        // Create XML writer
67        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
68
69        // XML header
70        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
71
72        // c:chartSpace
73        $objWriter->startElement('c:chartSpace');
74        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
75        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
76        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
77
78        // c:date1904
79        $objWriter->startElement('c:date1904');
80        $objWriter->writeAttribute('val', '1');
81        $objWriter->endElement();
82
83        // c:lang
84        $objWriter->startElement('c:lang');
85        $objWriter->writeAttribute('val', 'en-US');
86        $objWriter->endElement();
87
88        // c:chart
89        $objWriter->startElement('c:chart');
90
91        // Title?
92        if ($chart->getTitle()->isVisible()) {
93            // Write title
94            $this->writeTitle($objWriter, $chart->getTitle());
95        }
96
97        // c:autoTitleDeleted
98        $objWriter->startElement('c:autoTitleDeleted');
99        $objWriter->writeAttribute('val', $chart->getTitle()->isVisible() ? '0' : '1');
100        $objWriter->endElement();
101
102        // c:view3D
103        $objWriter->startElement('c:view3D');
104
105        // c:rotX
106        $objWriter->startElement('c:rotX');
107        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationX());
108        $objWriter->endElement();
109
110        // c:hPercent
111        $hPercent = $chart->getView3D()->getHeightPercent();
112        $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent);
113
114        // c:rotY
115        $objWriter->startElement('c:rotY');
116        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationY());
117        $objWriter->endElement();
118
119        // c:depthPercent
120        $objWriter->startElement('c:depthPercent');
121        $objWriter->writeAttribute('val', $chart->getView3D()->getDepthPercent());
122        $objWriter->endElement();
123
124        // c:rAngAx
125        $objWriter->startElement('c:rAngAx');
126        $objWriter->writeAttribute('val', $chart->getView3D()->hasRightAngleAxes() ? '1' : '0');
127        $objWriter->endElement();
128
129        // c:perspective
130        $objWriter->startElement('c:perspective');
131        $objWriter->writeAttribute('val', $chart->getView3D()->getPerspective());
132        $objWriter->endElement();
133
134        $objWriter->endElement();
135
136        // Write plot area
137        $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart);
138
139        // Legend?
140        if ($chart->getLegend()->isVisible()) {
141            // Write legend
142            $this->writeLegend($objWriter, $chart->getLegend());
143        }
144
145        // c:plotVisOnly
146        $objWriter->startElement('c:plotVisOnly');
147        $objWriter->writeAttribute('val', '1');
148        $objWriter->endElement();
149
150        // c:dispBlanksAs
151        $objWriter->startElement('c:dispBlanksAs');
152        $objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
153        $objWriter->endElement();
154
155        $objWriter->endElement();
156
157        // c:spPr
158        $objWriter->startElement('c:spPr');
159
160        // Fill
161        $this->writeFill($objWriter, $chart->getFill());
162
163        // Border
164        if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) {
165            $this->writeBorder($objWriter, $chart->getBorder(), '');
166        }
167
168        // Shadow
169        if ($chart->getShadow()->isVisible()) {
170            // a:effectLst
171            $objWriter->startElement('a:effectLst');
172
173            // a:outerShdw
174            $objWriter->startElement('a:outerShdw');
175            $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius()));
176            $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance()));
177            $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle($chart->getShadow()->getDirection()));
178            $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment());
179            $objWriter->writeAttribute('rotWithShape', '0');
180
181            $this->writeColor($objWriter, $chart->getShadow()->getColor(), $chart->getShadow()->getAlpha());
182
183            $objWriter->endElement();
184
185            $objWriter->endElement();
186        }
187
188        $objWriter->endElement();
189
190        // External data?
191        if ($chart->hasIncludedSpreadsheet()) {
192            // c:externalData
193            $objWriter->startElement('c:externalData');
194            $objWriter->writeAttribute('r:id', 'rId1');
195
196            // c:autoUpdate
197            $objWriter->startElement('c:autoUpdate');
198            $objWriter->writeAttribute('val', '0');
199            $objWriter->endElement();
200
201            $objWriter->endElement();
202        }
203
204        $objWriter->endElement();
205
206        // Return
207        return $objWriter->getData();
208    }
209
210    /**
211     * Write chart to XML format.
212     *
213     * @return string String output
214     *
215     * @throws \Exception
216     */
217    public function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string
218    {
219        // Need output?
220        if (!$chart->hasIncludedSpreadsheet()) {
221            throw new \Exception('No spreadsheet output is required for the given chart.');
222        }
223
224        // Create new spreadsheet
225        $spreadsheet = new Spreadsheet();
226
227        // Set properties
228        $title = $chart->getTitle()->getText();
229        if (0 == strlen($title)) {
230            $title = 'Chart';
231        }
232        $spreadsheet->getProperties()
233            ->setCreator(
234                $presentation->getDocumentProperties()->getCreator())->setLastModifiedBy(
235                    $presentation->getDocumentProperties()->getLastModifiedBy()
236                )
237            ->setTitle($title);
238
239        // Add chart data
240        $sheet = $spreadsheet->setActiveSheetIndex(0);
241        $sheet->setTitle('Sheet1');
242
243        // Write series
244        $seriesIndex = 0;
245        foreach ($chart->getPlotArea()->getType()->getSeries() as $series) {
246            // Title
247            $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, 1, $series->getTitle());
248
249            // X-axis
250            $axisXData = array_keys($series->getValues());
251            $numAxisXData = count($axisXData);
252            for ($i = 0; $i < $numAxisXData; ++$i) {
253                $sheet->setCellValueByColumnAndRow(0, $i + 2, $axisXData[$i]);
254            }
255
256            // Y-axis
257            $axisYData = array_values($series->getValues());
258            $numAxisYData = count($axisYData);
259            for ($i = 0; $i < $numAxisYData; ++$i) {
260                $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, $i + 2, $axisYData[$i]);
261            }
262
263            ++$seriesIndex;
264        }
265
266        // Save to string
267        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
268        $writer->save($tempName);
269
270        // Load file in memory
271        $returnValue = file_get_contents($tempName);
272        if (false === @unlink($tempName)) {
273            throw new \Exception('The file ' . $tempName . ' could not removed.');
274        }
275
276        return $returnValue;
277    }
278
279    /**
280     * Write element with value attribute.
281     *
282     * @param XMLWriter $objWriter XML Writer
283     */
284    protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void
285    {
286        $objWriter->startElement($elementName);
287        $objWriter->writeAttribute('val', $value);
288        $objWriter->endElement();
289    }
290
291    /**
292     * Write single value or reference.
293     *
294     * @param XMLWriter $objWriter XML Writer
295     */
296    protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void
297    {
298        if (!$isReference) {
299            // Value
300            $objWriter->writeElement('c:v', $value);
301
302            return;
303        }
304
305        // Reference and cache
306        // c:strRef
307        $objWriter->startElement('c:strRef');
308        // c:strRef/c:f
309        $objWriter->writeElement('c:f', $reference);
310        // c:strRef/c:strCache
311        $objWriter->startElement('c:strCache');
312        // c:strRef/c:strCache/c:ptCount
313        $objWriter->startElement('c:ptCount');
314        $objWriter->writeAttribute('val', '1');
315        $objWriter->endElement();
316
317        // c:strRef/c:strCache/c:pt
318        $objWriter->startElement('c:pt');
319        $objWriter->writeAttribute('idx', '0');
320        // c:strRef/c:strCache/c:pt/c:v
321        $objWriter->writeElement('c:v', $value);
322        // c:strRef/c:strCache/c:pt
323        $objWriter->endElement();
324        // c:strRef/c:strCache
325        $objWriter->endElement();
326        // c:strRef
327        $objWriter->endElement();
328    }
329
330    /**
331     * Write series value or reference.
332     *
333     * @param XMLWriter $objWriter XML Writer
334     * @param array<int, mixed> $values
335     */
336    protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void
337    {
338        // c:strLit / c:numLit
339        // c:strRef / c:numRef
340        $referenceType = ($isReference ? 'Ref' : 'Lit');
341        $dataType = is_numeric($values[0]) ? 'num' : 'str';
342        $objWriter->startElement('c:' . $dataType . $referenceType);
343
344        $numValues = count($values);
345        if (!$isReference) {
346            // Value
347
348            // c:ptCount
349            $objWriter->startElement('c:ptCount');
350            $objWriter->writeAttribute('val', count($values));
351            $objWriter->endElement();
352
353            // Add points
354            for ($i = 0; $i < $numValues; ++$i) {
355                // c:pt
356                $objWriter->startElement('c:pt');
357                $objWriter->writeAttribute('idx', $i);
358                $objWriter->writeElement('c:v', $values[$i]);
359                $objWriter->endElement();
360            }
361        } else {
362            // Reference
363            $objWriter->writeElement('c:f', $reference);
364            $objWriter->startElement('c:' . $dataType . 'Cache');
365
366            // c:ptCount
367            $objWriter->startElement('c:ptCount');
368            $objWriter->writeAttribute('val', count($values));
369            $objWriter->endElement();
370
371            // Add points
372            for ($i = 0; $i < $numValues; ++$i) {
373                // c:pt
374                $objWriter->startElement('c:pt');
375                $objWriter->writeAttribute('idx', $i);
376                $objWriter->writeElement('c:v', $values[$i]);
377                $objWriter->endElement();
378            }
379
380            $objWriter->endElement();
381        }
382
383        $objWriter->endElement();
384    }
385
386    /**
387     * Write Title.
388     *
389     * @param XMLWriter $objWriter XML Writer
390     *
391     * @throws \Exception
392     */
393    protected function writeTitle(XMLWriter $objWriter, Title $subject): void
394    {
395        // c:title
396        $objWriter->startElement('c:title');
397
398        // c:tx
399        $objWriter->startElement('c:tx');
400
401        // c:rich
402        $objWriter->startElement('c:rich');
403
404        // a:bodyPr
405        $objWriter->writeElement('a:bodyPr', null);
406
407        // a:lstStyle
408        $objWriter->writeElement('a:lstStyle', null);
409
410        // a:p
411        $objWriter->startElement('a:p');
412
413        // a:pPr
414        $objWriter->startElement('a:pPr');
415        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
416        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
417        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
418        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
419        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
420        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
421
422        // a:defRPr
423        $objWriter->writeElement('a:defRPr', null);
424
425        $objWriter->endElement();
426
427        // a:r
428        $objWriter->startElement('a:r');
429
430        // a:rPr
431        $objWriter->startElement('a:rPr');
432        $objWriter->writeAttribute('lang', 'en-US');
433        $objWriter->writeAttribute('dirty', '0');
434        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
435        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
436        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
437        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
438        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
439        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
440        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
441
442        // Font - a:solidFill
443        $objWriter->startElement('a:solidFill');
444
445        $this->writeColor($objWriter, $subject->getFont()->getColor());
446
447        $objWriter->endElement();
448
449        // Font - a:latin
450        $objWriter->startElement('a:latin');
451        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
452        $objWriter->endElement();
453
454        $objWriter->endElement();
455
456        // a:t
457        $objWriter->writeElement('a:t', $subject->getText());
458
459        $objWriter->endElement();
460
461        // a:endParaRPr
462        $objWriter->startElement('a:endParaRPr');
463        $objWriter->writeAttribute('lang', 'en-US');
464        $objWriter->writeAttribute('dirty', '0');
465        $objWriter->endElement();
466
467        $objWriter->endElement();
468
469        $objWriter->endElement();
470
471        $objWriter->endElement();
472
473        // Write layout
474        $this->writeLayout($objWriter, $subject);
475
476        // c:overlay
477        $objWriter->startElement('c:overlay');
478        $objWriter->writeAttribute('val', '0');
479        $objWriter->endElement();
480
481        $objWriter->endElement();
482    }
483
484    /**
485     * Write Plot Area.
486     *
487     * @param XMLWriter $objWriter XML Writer
488     *
489     * @throws \Exception
490     */
491    protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void
492    {
493        // c:plotArea
494        $objWriter->startElement('c:plotArea');
495
496        // Write layout
497        $this->writeLayout($objWriter, $subject);
498
499        // Write chart
500        $chartType = $subject->getType();
501        if ($chartType instanceof Area) {
502            $this->writeTypeArea($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
503        } elseif ($chartType instanceof Bar) {
504            $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
505        } elseif ($chartType instanceof Bar3D) {
506            $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
507        } elseif ($chartType instanceof Doughnut) {
508            $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
509        } elseif ($chartType instanceof Pie) {
510            $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
511        } elseif ($chartType instanceof Pie3D) {
512            $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
513        } elseif ($chartType instanceof Line) {
514            $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
515        } elseif ($chartType instanceof Radar) {
516            $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
517        } elseif ($chartType instanceof Scatter) {
518            $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
519        } else {
520            throw new \Exception('The chart type provided could not be rendered.');
521        }
522
523        // Write X axis?
524        if ($chartType->hasAxisX()) {
525            $this->writeAxis($objWriter, $subject->getAxisX(), Chart\Axis::AXIS_X, $chartType);
526        }
527
528        // Write Y axis?
529        if ($chartType->hasAxisY()) {
530            $this->writeAxis($objWriter, $subject->getAxisY(), Chart\Axis::AXIS_Y, $chartType);
531        }
532
533        $objWriter->endElement();
534    }
535
536    /**
537     * Write Legend.
538     *
539     * @param XMLWriter $objWriter XML Writer
540     * @param Chart\Legend $subject
541     *
542     * @throws \Exception
543     */
544    protected function writeLegend(XMLWriter $objWriter, Legend $subject): void
545    {
546        // c:legend
547        $objWriter->startElement('c:legend');
548
549        // c:legendPos
550        $objWriter->startElement('c:legendPos');
551        $objWriter->writeAttribute('val', $subject->getPosition());
552        $objWriter->endElement();
553
554        // Write layout
555        $this->writeLayout($objWriter, $subject);
556
557        // c:overlay
558        $objWriter->startElement('c:overlay');
559        $objWriter->writeAttribute('val', '0');
560        $objWriter->endElement();
561
562        // c:spPr
563        $objWriter->startElement('c:spPr');
564
565        // Fill
566        $this->writeFill($objWriter, $subject->getFill());
567
568        // Border
569        if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) {
570            $this->writeBorder($objWriter, $subject->getBorder(), '');
571        }
572
573        $objWriter->endElement();
574
575        // c:txPr
576        $objWriter->startElement('c:txPr');
577
578        // a:bodyPr
579        $objWriter->writeElement('a:bodyPr', null);
580
581        // a:lstStyle
582        $objWriter->writeElement('a:lstStyle', null);
583
584        // a:p
585        $objWriter->startElement('a:p');
586
587        // a:pPr
588        $objWriter->startElement('a:pPr');
589        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
590        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
591        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
592        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
593        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
594        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
595
596        // a:defRPr
597        $objWriter->startElement('a:defRPr');
598
599        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
600        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
601        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
602        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
603        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
604        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
605        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
606
607        // Font - a:solidFill
608        $objWriter->startElement('a:solidFill');
609
610        $this->writeColor($objWriter, $subject->getFont()->getColor());
611
612        $objWriter->endElement();
613
614        // Font - a:latin
615        $objWriter->startElement('a:latin');
616        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
617        $objWriter->endElement();
618
619        $objWriter->endElement();
620
621        $objWriter->endElement();
622
623        // a:endParaRPr
624        $objWriter->startElement('a:endParaRPr');
625        $objWriter->writeAttribute('lang', 'en-US');
626        $objWriter->writeAttribute('dirty', '0');
627        $objWriter->endElement();
628
629        $objWriter->endElement();
630
631        $objWriter->endElement();
632
633        $objWriter->endElement();
634    }
635
636    /**
637     * Write Layout.
638     *
639     * @param XMLWriter $objWriter XML Writer
640     * @param Legend|PlotArea|Title $subject
641     *
642     * @throws \Exception
643     */
644    protected function writeLayout(XMLWriter $objWriter, $subject): void
645    {
646        // c:layout
647        $objWriter->startElement('c:layout');
648
649        // c:manualLayout
650        $objWriter->startElement('c:manualLayout');
651        // c:xMode
652        $objWriter->startElement('c:xMode');
653        $objWriter->writeAttribute('val', 'edge');
654        $objWriter->endElement();
655
656        // c:yMode
657        $objWriter->startElement('c:yMode');
658        $objWriter->writeAttribute('val', 'edge');
659        $objWriter->endElement();
660
661        if (0 != $subject->getOffsetX()) {
662            // c:x
663            $objWriter->startElement('c:x');
664            $objWriter->writeAttribute('val', $subject->getOffsetX());
665            $objWriter->endElement();
666        }
667
668        if (0 != $subject->getOffsetY()) {
669            // c:y
670            $objWriter->startElement('c:y');
671            $objWriter->writeAttribute('val', $subject->getOffsetY());
672            $objWriter->endElement();
673        }
674
675        if (0 != $subject->getWidth()) {
676            // c:w
677            $objWriter->startElement('c:w');
678            $objWriter->writeAttribute('val', $subject->getWidth());
679            $objWriter->endElement();
680        }
681
682        if (0 != $subject->getHeight()) {
683            // c:h
684            $objWriter->startElement('c:h');
685            $objWriter->writeAttribute('val', $subject->getHeight());
686            $objWriter->endElement();
687        }
688
689        $objWriter->endElement();
690        $objWriter->endElement();
691    }
692
693    /**
694     * Write Type Area.
695     *
696     * @param XMLWriter $objWriter XML Writer
697     * @param Chart\Type\Area $subject
698     *
699     * @throws \Exception
700     */
701    protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void
702    {
703        // c:lineChart
704        $objWriter->startElement('c:areaChart');
705
706        // c:grouping
707        $objWriter->startElement('c:grouping');
708        $objWriter->writeAttribute('val', 'standard');
709        $objWriter->endElement();
710
711        // Write series
712        $seriesIndex = 0;
713        foreach ($subject->getSeries() as $series) {
714            // c:ser
715            $objWriter->startElement('c:ser');
716
717            // c:ser > c:idx
718            $objWriter->startElement('c:idx');
719            $objWriter->writeAttribute('val', $seriesIndex);
720            $objWriter->endElement();
721
722            // c:ser > c:order
723            $objWriter->startElement('c:order');
724            $objWriter->writeAttribute('val', $seriesIndex);
725            $objWriter->endElement();
726
727            // c:ser > c:tx
728            $objWriter->startElement('c:tx');
729            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
730            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
731            $objWriter->endElement();
732
733            // c:ser > c:dLbls
734            // @link : https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.areachartseries.aspx
735            $objWriter->startElement('c:dLbls');
736
737            // c:ser > c:dLbls > c:showVal
738            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
739
740            // c:ser > c:dLbls > c:showCatName
741            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
742
743            // c:ser > c:dLbls > c:showSerName
744            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
745
746            // c:ser > c:dLbls > c:showPercent
747            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
748
749            // c:ser > ##c:dLbls
750            $objWriter->endElement();
751
752            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
753                // c:spPr
754                $objWriter->startElement('c:spPr');
755                // Write fill
756                $this->writeFill($objWriter, $series->getFill());
757                // ## c:spPr
758                $objWriter->endElement();
759            }
760
761            // Write X axis data
762            $axisXData = array_keys($series->getValues());
763
764            // c:cat
765            $objWriter->startElement('c:cat');
766            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
767            $objWriter->endElement();
768
769            // Write Y axis data
770            $axisYData = array_values($series->getValues());
771
772            // c:val
773            $objWriter->startElement('c:val');
774            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
775            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
776            $objWriter->endElement();
777
778            $objWriter->endElement();
779
780            ++$seriesIndex;
781        }
782
783        // c:axId
784        $objWriter->startElement('c:axId');
785        $objWriter->writeAttribute('val', '52743552');
786        $objWriter->endElement();
787
788        // c:axId
789        $objWriter->startElement('c:axId');
790        $objWriter->writeAttribute('val', '52749440');
791        $objWriter->endElement();
792
793        $objWriter->endElement();
794    }
795
796    /**
797     * Write Type Bar.
798     *
799     * @param XMLWriter $objWriter XML Writer
800     * @param Chart\Type\Bar $subject
801     *
802     * @throws \Exception
803     */
804    protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void
805    {
806        // c:barChart
807        $objWriter->startElement('c:barChart');
808
809        // c:barDir
810        $objWriter->startElement('c:barDir');
811        $objWriter->writeAttribute('val', $subject->getBarDirection());
812        $objWriter->endElement();
813
814        // c:grouping
815        $objWriter->startElement('c:grouping');
816        $objWriter->writeAttribute('val', $subject->getBarGrouping());
817        $objWriter->endElement();
818
819        // Write series
820        $seriesIndex = 0;
821        foreach ($subject->getSeries() as $series) {
822            // c:ser
823            $objWriter->startElement('c:ser');
824
825            // c:idx
826            $objWriter->startElement('c:idx');
827            $objWriter->writeAttribute('val', $seriesIndex);
828            $objWriter->endElement();
829
830            // c:order
831            $objWriter->startElement('c:order');
832            $objWriter->writeAttribute('val', $seriesIndex);
833            $objWriter->endElement();
834
835            // c:tx
836            $objWriter->startElement('c:tx');
837            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
838            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
839            $objWriter->endElement();
840
841            // Fills for points?
842            $dataPointFills = $series->getDataPointFills();
843            foreach ($dataPointFills as $key => $value) {
844                // c:dPt
845                $objWriter->startElement('c:dPt');
846
847                // c:idx
848                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
849
850                if (Fill::FILL_NONE != $value->getFillType()) {
851                    // c:spPr
852                    $objWriter->startElement('c:spPr');
853                    // Write fill
854                    $this->writeFill($objWriter, $value);
855                    // ## c:spPr
856                    $objWriter->endElement();
857                }
858
859                // ## c:dPt
860                $objWriter->endElement();
861            }
862
863            // c:dLbls
864            $objWriter->startElement('c:dLbls');
865
866            if ($series->hasDlblNumFormat()) {
867                //c:numFmt
868                $objWriter->startElement('c:numFmt');
869                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
870                $objWriter->writeAttribute('sourceLinked', '0');
871                $objWriter->endElement();
872            }
873
874            // c:txPr
875            $objWriter->startElement('c:txPr');
876
877            // a:bodyPr
878            $objWriter->writeElement('a:bodyPr');
879
880            // a:lstStyle
881            $objWriter->writeElement('a:lstStyle');
882
883            // a:p
884            $objWriter->startElement('a:p');
885
886            // a:pPr
887            $objWriter->startElement('a:pPr');
888
889            // a:defRPr
890            $objWriter->startElement('a:defRPr');
891
892            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
893            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
894            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
895            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
896            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
897            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
898            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
899
900            // a:solidFill
901            $objWriter->startElement('a:solidFill');
902            $this->writeColor($objWriter, $series->getFont()->getColor());
903            // >a:solidFill
904            $objWriter->endElement();
905            // a:latin
906            $objWriter->startElement('a:latin');
907            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
908            // >a:latin
909            $objWriter->endElement();
910
911            // >a:defRPr
912            $objWriter->endElement();
913            // >a:pPr
914            $objWriter->endElement();
915
916            // a:endParaRPr
917            $objWriter->startElement('a:endParaRPr');
918            $objWriter->writeAttribute('lang', 'en-US');
919            $objWriter->writeAttribute('dirty', '0');
920            $objWriter->endElement();
921
922            // >a:p
923            $objWriter->endElement();
924            // >a:lstStyle
925            $objWriter->endElement();
926
927            // c:dLblPos
928            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
929
930            // c:showVal
931            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
932
933            // c:showCatName
934            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
935
936            // c:showSerName
937            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
938
939            // c:showPercent
940            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
941
942            // c:separator
943            $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : '');
944
945            // c:showLeaderLines
946            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
947
948            $objWriter->endElement();
949
950            // c:spPr
951            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
952                // c:spPr
953                $objWriter->startElement('c:spPr');
954                // Write fill
955                $this->writeFill($objWriter, $series->getFill());
956                // ## c:spPr
957                $objWriter->endElement();
958            }
959
960            // Write X axis data
961            $axisXData = array_keys($series->getValues());
962
963            // c:cat
964            $objWriter->startElement('c:cat');
965            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
966            $objWriter->endElement();
967
968            // Write Y axis data
969            $axisYData = array_values($series->getValues());
970
971            // c:val
972            $objWriter->startElement('c:val');
973            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
974            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
975            $objWriter->endElement();
976
977            $objWriter->endElement();
978
979            ++$seriesIndex;
980        }
981
982        // c:gapWidth
983        $objWriter->startElement('c:gapWidth');
984        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
985        $objWriter->endElement();
986
987        // c:overlap
988        $barGrouping = $subject->getBarGrouping();
989        $objWriter->startElement('c:overlap');
990        if (Bar::GROUPING_CLUSTERED === $barGrouping) {
991            $objWriter->writeAttribute('val', '0');
992        } elseif (Bar::GROUPING_STACKED === $barGrouping || Bar::GROUPING_PERCENTSTACKED === $barGrouping) {
993            $objWriter->writeAttribute('val', '100');
994        }
995        $objWriter->endElement();
996
997        // c:axId
998        $objWriter->startElement('c:axId');
999        $objWriter->writeAttribute('val', '52743552');
1000        $objWriter->endElement();
1001
1002        // c:axId
1003        $objWriter->startElement('c:axId');
1004        $objWriter->writeAttribute('val', '52749440');
1005        $objWriter->endElement();
1006
1007        // c:extLst
1008        $objWriter->startElement('c:extLst');
1009        $objWriter->endElement();
1010
1011        $objWriter->endElement();
1012    }
1013
1014    /**
1015     * Write Type Bar3D.
1016     *
1017     * @param XMLWriter $objWriter XML Writer
1018     * @param Chart\Type\Bar3D $subject
1019     *
1020     * @throws \Exception
1021     */
1022    protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void
1023    {
1024        // c:bar3DChart
1025        $objWriter->startElement('c:bar3DChart');
1026
1027        // c:barDir
1028        $objWriter->startElement('c:barDir');
1029        $objWriter->writeAttribute('val', $subject->getBarDirection());
1030        $objWriter->endElement();
1031
1032        // c:grouping
1033        $objWriter->startElement('c:grouping');
1034        $objWriter->writeAttribute('val', $subject->getBarGrouping());
1035        $objWriter->endElement();
1036
1037        // Write series
1038        $seriesIndex = 0;
1039        foreach ($subject->getSeries() as $series) {
1040            // c:ser
1041            $objWriter->startElement('c:ser');
1042
1043            // c:idx
1044            $objWriter->startElement('c:idx');
1045            $objWriter->writeAttribute('val', $seriesIndex);
1046            $objWriter->endElement();
1047
1048            // c:order
1049            $objWriter->startElement('c:order');
1050            $objWriter->writeAttribute('val', $seriesIndex);
1051            $objWriter->endElement();
1052
1053            // c:tx
1054            $objWriter->startElement('c:tx');
1055            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1056            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1057            $objWriter->endElement();
1058
1059            // Fills for points?
1060            $dataPointFills = $series->getDataPointFills();
1061            foreach ($dataPointFills as $key => $value) {
1062                // c:dPt
1063                $objWriter->startElement('c:dPt');
1064
1065                // c:idx
1066                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
1067
1068                if (Fill::FILL_NONE != $value->getFillType()) {
1069                    // c:spPr
1070                    $objWriter->startElement('c:spPr');
1071                    // Write fill
1072                    $this->writeFill($objWriter, $value);
1073                    // ## c:spPr
1074                    $objWriter->endElement();
1075                }
1076
1077                // ## c:dPt
1078                $objWriter->endElement();
1079            }
1080
1081            // c:dLbls
1082            $objWriter->startElement('c:dLbls');
1083
1084            // c:txPr
1085            $objWriter->startElement('c:txPr');
1086
1087            // a:bodyPr
1088            $objWriter->writeElement('a:bodyPr', null);
1089
1090            // a:lstStyle
1091            $objWriter->writeElement('a:lstStyle', null);
1092
1093            // a:p
1094            $objWriter->startElement('a:p');
1095
1096            // a:pPr
1097            $objWriter->startElement('a:pPr');
1098
1099            // a:defRPr
1100            $objWriter->startElement('a:defRPr');
1101
1102            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1103            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1104            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1105            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1106            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1107            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1108            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1109
1110            // Font - a:solidFill
1111            $objWriter->startElement('a:solidFill');
1112
1113            $this->writeColor($objWriter, $series->getFont()->getColor());
1114
1115            $objWriter->endElement();
1116
1117            // Font - a:latin
1118            $objWriter->startElement('a:latin');
1119            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1120            $objWriter->endElement();
1121
1122            $objWriter->endElement();
1123
1124            $objWriter->endElement();
1125
1126            // a:endParaRPr
1127            $objWriter->startElement('a:endParaRPr');
1128            $objWriter->writeAttribute('lang', 'en-US');
1129            $objWriter->writeAttribute('dirty', '0');
1130            $objWriter->endElement();
1131
1132            $objWriter->endElement();
1133
1134            $objWriter->endElement();
1135
1136            // c:showVal
1137            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1138
1139            // c:showCatName
1140            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1141
1142            // c:showSerName
1143            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1144
1145            // c:showPercent
1146            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1147
1148            // c:showLeaderLines
1149            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1150
1151            $objWriter->endElement();
1152
1153            // c:spPr
1154            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
1155                // c:spPr
1156                $objWriter->startElement('c:spPr');
1157                // Write fill
1158                $this->writeFill($objWriter, $series->getFill());
1159                // ## c:spPr
1160                $objWriter->endElement();
1161            }
1162
1163            // Write X axis data
1164            $axisXData = array_keys($series->getValues());
1165
1166            // c:cat
1167            $objWriter->startElement('c:cat');
1168            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1169            $objWriter->endElement();
1170
1171            // Write Y axis data
1172            $axisYData = array_values($series->getValues());
1173
1174            // c:val
1175            $objWriter->startElement('c:val');
1176            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1177            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1178            $objWriter->endElement();
1179
1180            $objWriter->endElement();
1181
1182            ++$seriesIndex;
1183        }
1184
1185        // c:gapWidth
1186        $objWriter->startElement('c:gapWidth');
1187        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1188        $objWriter->endElement();
1189
1190        // c:axId
1191        $objWriter->startElement('c:axId');
1192        $objWriter->writeAttribute('val', '52743552');
1193        $objWriter->endElement();
1194
1195        // c:axId
1196        $objWriter->startElement('c:axId');
1197        $objWriter->writeAttribute('val', '52749440');
1198        $objWriter->endElement();
1199
1200        // c:axId
1201        $objWriter->startElement('c:axId');
1202        $objWriter->writeAttribute('val', '0');
1203        $objWriter->endElement();
1204
1205        $objWriter->endElement();
1206    }
1207
1208    /**
1209     * Write Type Pie.
1210     *
1211     * @param XMLWriter $objWriter XML Writer
1212     *
1213     * @throws \Exception
1214     */
1215    protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void
1216    {
1217        // c:pieChart
1218        $objWriter->startElement('c:doughnutChart');
1219
1220        // c:varyColors
1221        $objWriter->startElement('c:varyColors');
1222        $objWriter->writeAttribute('val', '1');
1223        $objWriter->endElement();
1224
1225        // Write series
1226        $seriesIndex = 0;
1227        foreach ($subject->getSeries() as $series) {
1228            // c:ser
1229            $objWriter->startElement('c:ser');
1230
1231            // c:idx
1232            $objWriter->startElement('c:idx');
1233            $objWriter->writeAttribute('val', $seriesIndex);
1234            $objWriter->endElement();
1235
1236            // c:order
1237            $objWriter->startElement('c:order');
1238            $objWriter->writeAttribute('val', $seriesIndex);
1239            $objWriter->endElement();
1240
1241            // c:tx
1242            $objWriter->startElement('c:tx');
1243            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1244            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1245            $objWriter->endElement();
1246
1247            // Fills for points?
1248            $dataPointFills = $series->getDataPointFills();
1249            foreach ($dataPointFills as $key => $value) {
1250                // c:dPt
1251                $objWriter->startElement('c:dPt');
1252                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
1253                // c:dPt/c:spPr
1254                $objWriter->startElement('c:spPr');
1255                $this->writeFill($objWriter, $value);
1256                // c:dPt/##c:spPr
1257                $objWriter->endElement();
1258                // ##c:dPt
1259                $objWriter->endElement();
1260            }
1261
1262            // Write X axis data
1263            $axisXData = array_keys($series->getValues());
1264
1265            // c:cat
1266            $objWriter->startElement('c:cat');
1267            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1268            $objWriter->endElement();
1269
1270            // Write Y axis data
1271            $axisYData = array_values($series->getValues());
1272
1273            // c:val
1274            $objWriter->startElement('c:val');
1275            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1276            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1277            $objWriter->endElement();
1278
1279            $objWriter->endElement();
1280
1281            ++$seriesIndex;
1282        }
1283
1284        if (isset($series) && is_object($series) && $series instanceof Chart\Series) {
1285            // c:dLbls
1286            $objWriter->startElement('c:dLbls');
1287
1288            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1289            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1290            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1291            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1292            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1293            $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0');
1294            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1295
1296            if ($series->hasDlblNumFormat()) {
1297                //c:numFmt
1298                $objWriter->startElement('c:numFmt');
1299                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1300                $objWriter->writeAttribute('sourceLinked', '0');
1301                $objWriter->endElement();
1302            }
1303
1304            // c:dLbls\c:txPr
1305            $objWriter->startElement('c:txPr');
1306            $objWriter->writeElement('a:bodyPr', null);
1307            $objWriter->writeElement('a:lstStyle', null);
1308
1309            // c:dLbls\c:txPr\a:p
1310            $objWriter->startElement('a:p');
1311
1312            // c:dLbls\c:txPr\a:p\a:pPr
1313            $objWriter->startElement('a:pPr');
1314
1315            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr
1316            $objWriter->startElement('a:defRPr');
1317            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1318            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1319            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1320            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1321            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1322            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1323            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1324
1325            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill
1326            $objWriter->startElement('a:solidFill');
1327            $this->writeColor($objWriter, $series->getFont()->getColor());
1328            $objWriter->endElement();
1329
1330            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin
1331            $objWriter->startElement('a:latin');
1332            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1333            $objWriter->endElement();
1334
1335            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\
1336            $objWriter->endElement();
1337            // c:dLbls\c:txPr\a:p\a:pPr\
1338            $objWriter->endElement();
1339
1340            // c:dLbls\c:txPr\a:p\a:endParaRPr
1341            $objWriter->startElement('a:endParaRPr');
1342            $objWriter->writeAttribute('lang', 'en-US');
1343            $objWriter->writeAttribute('dirty', '0');
1344            $objWriter->endElement();
1345
1346            // c:dLbls\c:txPr\a:p\
1347            $objWriter->endElement();
1348            // c:dLbls\c:txPr\
1349            $objWriter->endElement();
1350
1351            $separator = $series->getSeparator();
1352            if (!empty($separator) && PHP_EOL != $separator) {
1353                // c:dLbls\c:separator
1354                $objWriter->writeElement('c:separator', $separator);
1355            }
1356
1357            // c:dLbls\
1358            $objWriter->endElement();
1359        }
1360
1361        $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0');
1362        $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize());
1363
1364        $objWriter->endElement();
1365    }
1366
1367    /**
1368     * Write Type Pie.
1369     *
1370     * @param XMLWriter $objWriter XML Writer
1371     *
1372     * @throws \Exception
1373     */
1374    protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void
1375    {
1376        // c:pieChart
1377        $objWriter->startElement('c:pieChart');
1378
1379        // c:varyColors
1380        $objWriter->startElement('c:varyColors');
1381        $objWriter->writeAttribute('val', '1');
1382        $objWriter->endElement();
1383
1384        // Write series
1385        $seriesIndex = 0;
1386        foreach ($subject->getSeries() as $series) {
1387            // c:ser
1388            $objWriter->startElement('c:ser');
1389
1390            // c:idx
1391            $objWriter->startElement('c:idx');
1392            $objWriter->writeAttribute('val', $seriesIndex);
1393            $objWriter->endElement();
1394
1395            // c:order
1396            $objWriter->startElement('c:order');
1397            $objWriter->writeAttribute('val', $seriesIndex);
1398            $objWriter->endElement();
1399
1400            // c:tx
1401            $objWriter->startElement('c:tx');
1402            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1403            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1404            $objWriter->endElement();
1405
1406            // Fills for points?
1407            $dataPointFills = $series->getDataPointFills();
1408            foreach ($dataPointFills as $key => $value) {
1409                // c:dPt
1410                $objWriter->startElement('c:dPt');
1411                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
1412                // c:dPt/c:spPr
1413                $objWriter->startElement('c:spPr');
1414                $this->writeFill($objWriter, $value);
1415                // c:dPt/##c:spPr
1416                $objWriter->endElement();
1417                // ##c:dPt
1418                $objWriter->endElement();
1419            }
1420
1421            // c:dLbls
1422            $objWriter->startElement('c:dLbls');
1423
1424            if ($series->hasDlblNumFormat()) {
1425                //c:numFmt
1426                $objWriter->startElement('c:numFmt');
1427                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1428                $objWriter->writeAttribute('sourceLinked', '0');
1429                $objWriter->endElement();
1430            }
1431
1432            // c:txPr
1433            $objWriter->startElement('c:txPr');
1434
1435            // a:bodyPr
1436            $objWriter->writeElement('a:bodyPr', null);
1437
1438            // a:lstStyle
1439            $objWriter->writeElement('a:lstStyle', null);
1440
1441            // a:p
1442            $objWriter->startElement('a:p');
1443
1444            // a:pPr
1445            $objWriter->startElement('a:pPr');
1446
1447            // a:defRPr
1448            $objWriter->startElement('a:defRPr');
1449
1450            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1451            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1452            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1453            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1454            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1455            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1456            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1457
1458            // Font - a:solidFill
1459            $objWriter->startElement('a:solidFill');
1460
1461            $this->writeColor($objWriter, $series->getFont()->getColor());
1462
1463            $objWriter->endElement();
1464
1465            // Font - a:latin
1466            $objWriter->startElement('a:latin');
1467            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1468            $objWriter->endElement();
1469
1470            $objWriter->endElement();
1471
1472            $objWriter->endElement();
1473
1474            // a:endParaRPr
1475            $objWriter->startElement('a:endParaRPr');
1476            $objWriter->writeAttribute('lang', 'en-US');
1477            $objWriter->writeAttribute('dirty', '0');
1478            $objWriter->endElement();
1479
1480            $objWriter->endElement();
1481
1482            $objWriter->endElement();
1483
1484            // c:dLblPos
1485            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1486
1487            // c:showLegendKey
1488            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1489
1490            // c:showVal
1491            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1492
1493            // c:showCatName
1494            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1495
1496            // c:showSerName
1497            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1498
1499            // c:showPercent
1500            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1501
1502            // c:showLeaderLines
1503            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1504
1505            $objWriter->endElement();
1506
1507            // Write X axis data
1508            $axisXData = array_keys($series->getValues());
1509
1510            // c:cat
1511            $objWriter->startElement('c:cat');
1512            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1513            $objWriter->endElement();
1514
1515            // Write Y axis data
1516            $axisYData = array_values($series->getValues());
1517
1518            // c:val
1519            $objWriter->startElement('c:val');
1520            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1521            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1522            $objWriter->endElement();
1523
1524            $objWriter->endElement();
1525
1526            ++$seriesIndex;
1527        }
1528
1529        $objWriter->endElement();
1530    }
1531
1532    /**
1533     * Write Type Pie3D.
1534     *
1535     * @param XMLWriter $objWriter XML Writer
1536     *
1537     * @throws \Exception
1538     */
1539    protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void
1540    {
1541        // c:pie3DChart
1542        $objWriter->startElement('c:pie3DChart');
1543
1544        // c:varyColors
1545        $objWriter->startElement('c:varyColors');
1546        $objWriter->writeAttribute('val', '1');
1547        $objWriter->endElement();
1548
1549        // Write series
1550        $seriesIndex = 0;
1551        foreach ($subject->getSeries() as $series) {
1552            // c:ser
1553            $objWriter->startElement('c:ser');
1554
1555            // c:idx
1556            $objWriter->startElement('c:idx');
1557            $objWriter->writeAttribute('val', $seriesIndex);
1558            $objWriter->endElement();
1559
1560            // c:order
1561            $objWriter->startElement('c:order');
1562            $objWriter->writeAttribute('val', $seriesIndex);
1563            $objWriter->endElement();
1564
1565            // c:tx
1566            $objWriter->startElement('c:tx');
1567            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1568            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1569            $objWriter->endElement();
1570
1571            // c:explosion
1572            $objWriter->startElement('c:explosion');
1573            $objWriter->writeAttribute('val', $subject->getExplosion());
1574            $objWriter->endElement();
1575
1576            // Fills for points?
1577            $dataPointFills = $series->getDataPointFills();
1578            foreach ($dataPointFills as $key => $value) {
1579                // c:dPt
1580                $objWriter->startElement('c:dPt');
1581                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
1582                // c:dPt/c:spPr
1583                $objWriter->startElement('c:spPr');
1584                $this->writeFill($objWriter, $value);
1585                // c:dPt/##c:spPr
1586                $objWriter->endElement();
1587                // ##c:dPt
1588                $objWriter->endElement();
1589            }
1590
1591            // c:dLbls
1592            $objWriter->startElement('c:dLbls');
1593
1594            // c:txPr
1595            $objWriter->startElement('c:txPr');
1596
1597            // a:bodyPr
1598            $objWriter->writeElement('a:bodyPr', null);
1599
1600            // a:lstStyle
1601            $objWriter->writeElement('a:lstStyle', null);
1602
1603            // a:p
1604            $objWriter->startElement('a:p');
1605
1606            // a:pPr
1607            $objWriter->startElement('a:pPr');
1608
1609            // a:defRPr
1610            $objWriter->startElement('a:defRPr');
1611
1612            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1613            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1614            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1615            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1616            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1617            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1618            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1619
1620            // Font - a:solidFill
1621            $objWriter->startElement('a:solidFill');
1622
1623            $this->writeColor($objWriter, $series->getFont()->getColor());
1624
1625            $objWriter->endElement();
1626
1627            // Font - a:latin
1628            $objWriter->startElement('a:latin');
1629            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1630            $objWriter->endElement();
1631
1632            $objWriter->endElement();
1633
1634            $objWriter->endElement();
1635
1636            // a:endParaRPr
1637            $objWriter->startElement('a:endParaRPr');
1638            $objWriter->writeAttribute('lang', 'en-US');
1639            $objWriter->writeAttribute('dirty', '0');
1640            $objWriter->endElement();
1641
1642            $objWriter->endElement();
1643
1644            $objWriter->endElement();
1645
1646            // c:dLblPos
1647            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1648
1649            // c:showVal
1650            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1651
1652            // c:showCatName
1653            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1654
1655            // c:showSerName
1656            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1657
1658            // c:showPercent
1659            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1660
1661            // c:showLeaderLines
1662            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1663
1664            $objWriter->endElement();
1665
1666            // Write X axis data
1667            $axisXData = array_keys($series->getValues());
1668
1669            // c:cat
1670            $objWriter->startElement('c:cat');
1671            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1672            $objWriter->endElement();
1673
1674            // Write Y axis data
1675            $axisYData = array_values($series->getValues());
1676
1677            // c:val
1678            $objWriter->startElement('c:val');
1679            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1680            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1681            $objWriter->endElement();
1682
1683            $objWriter->endElement();
1684
1685            ++$seriesIndex;
1686        }
1687
1688        $objWriter->endElement();
1689    }
1690
1691    /**
1692     * Write Type Line.
1693     *
1694     * @param XMLWriter $objWriter XML Writer
1695     *
1696     * @throws \Exception
1697     */
1698    protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void
1699    {
1700        // c:lineChart
1701        $objWriter->startElement('c:lineChart');
1702
1703        // c:grouping
1704        $objWriter->startElement('c:grouping');
1705        $objWriter->writeAttribute('val', 'standard');
1706        $objWriter->endElement();
1707
1708        // Write series
1709        $seriesIndex = 0;
1710        foreach ($subject->getSeries() as $series) {
1711            // c:ser
1712            $objWriter->startElement('c:ser');
1713
1714            // c:idx
1715            $objWriter->startElement('c:idx');
1716            $objWriter->writeAttribute('val', $seriesIndex);
1717            $objWriter->endElement();
1718
1719            // c:order
1720            $objWriter->startElement('c:order');
1721            $objWriter->writeAttribute('val', $seriesIndex);
1722            $objWriter->endElement();
1723
1724            // c:tx
1725            $objWriter->startElement('c:tx');
1726            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1727            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1728            $objWriter->endElement();
1729
1730            // c:spPr
1731            $objWriter->startElement('c:spPr');
1732            // Write fill
1733            $this->writeFill($objWriter, $series->getFill());
1734            // Write outline
1735            $this->writeOutline($objWriter, $series->getOutline());
1736            // ## c:spPr
1737            $objWriter->endElement();
1738
1739            // Marker
1740            $this->writeSeriesMarker($objWriter, $series->getMarker());
1741
1742            // c:dLbls
1743            $objWriter->startElement('c:dLbls');
1744
1745            // c:txPr
1746            $objWriter->startElement('c:txPr');
1747
1748            // a:bodyPr
1749            $objWriter->writeElement('a:bodyPr', null);
1750
1751            // a:lstStyle
1752            $objWriter->writeElement('a:lstStyle', null);
1753
1754            // a:p
1755            $objWriter->startElement('a:p');
1756
1757            // a:pPr
1758            $objWriter->startElement('a:pPr');
1759
1760            // a:defRPr
1761            $objWriter->startElement('a:defRPr');
1762
1763            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1764            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1765            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1766            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1767            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1768            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1769            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1770
1771            // Font - a:solidFill
1772            $objWriter->startElement('a:solidFill');
1773
1774            $this->writeColor($objWriter, $series->getFont()->getColor());
1775
1776            $objWriter->endElement();
1777
1778            // Font - a:latin
1779            $objWriter->startElement('a:latin');
1780            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1781            $objWriter->endElement();
1782
1783            $objWriter->endElement();
1784
1785            $objWriter->endElement();
1786
1787            // a:endParaRPr
1788            $objWriter->startElement('a:endParaRPr');
1789            $objWriter->writeAttribute('lang', 'en-US');
1790            $objWriter->writeAttribute('dirty', '0');
1791            $objWriter->endElement();
1792
1793            $objWriter->endElement();
1794
1795            $objWriter->endElement();
1796
1797            // c:showVal
1798            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1799
1800            // c:showCatName
1801            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1802
1803            // c:showSerName
1804            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1805
1806            // c:showPercent
1807            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1808
1809            // c:showLeaderLines
1810            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1811
1812            // > c:dLbls
1813            $objWriter->endElement();
1814
1815            // Write X axis data
1816            $axisXData = array_keys($series->getValues());
1817
1818            // c:cat
1819            $objWriter->startElement('c:cat');
1820            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1821            $objWriter->endElement();
1822
1823            // Write Y axis data
1824            $axisYData = array_values($series->getValues());
1825
1826            // c:val
1827            $objWriter->startElement('c:val');
1828            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1829            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1830            $objWriter->endElement();
1831
1832            // c:smooth
1833            $objWriter->startElement('c:smooth');
1834            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
1835            $objWriter->endElement();
1836
1837            $objWriter->endElement();
1838
1839            ++$seriesIndex;
1840        }
1841
1842        // c:marker
1843        $objWriter->startElement('c:marker');
1844        $objWriter->writeAttribute('val', '1');
1845        $objWriter->endElement();
1846
1847        // c:axId
1848        $objWriter->startElement('c:axId');
1849        $objWriter->writeAttribute('val', '52743552');
1850        $objWriter->endElement();
1851
1852        // c:axId
1853        $objWriter->startElement('c:axId');
1854        $objWriter->writeAttribute('val', '52749440');
1855        $objWriter->endElement();
1856
1857        $objWriter->endElement();
1858    }
1859
1860    /**
1861     * Write Type Radar
1862     *
1863     * @param XMLWriter $objWriter XML Writer
1864     * @param Radar $subject
1865     * @param bool $includeSheet
1866     *
1867     * @throws \Exception
1868     */
1869    protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void
1870    {
1871        // c:scatterChart
1872        $objWriter->startElement('c:radarChart');
1873
1874        // c:radarStyle
1875        $objWriter->startElement('c:radarStyle');
1876        $objWriter->writeAttribute('val', 'marker');
1877        $objWriter->endElement();
1878
1879        // c:varyColors
1880        $objWriter->startElement('c:varyColors');
1881        $objWriter->writeAttribute('val', '0');
1882        $objWriter->endElement();
1883
1884        // Write series
1885        $seriesIndex = 0;
1886        foreach ($subject->getSeries() as $series) {
1887            // c:ser
1888            $objWriter->startElement('c:ser');
1889
1890            // c:idx
1891            $objWriter->startElement('c:idx');
1892            $objWriter->writeAttribute('val', $seriesIndex);
1893            $objWriter->endElement();
1894
1895            // c:order
1896            $objWriter->startElement('c:order');
1897            $objWriter->writeAttribute('val', $seriesIndex);
1898            $objWriter->endElement();
1899
1900            // c:tx
1901            $objWriter->startElement('c:tx');
1902            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1903            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1904            $objWriter->endElement();
1905
1906            // Marker
1907            $this->writeSeriesMarker($objWriter, $series->getMarker());
1908
1909            // c:dLbls
1910            $objWriter->startElement('c:dLbls');
1911
1912            // c:txPr
1913            $objWriter->startElement('c:txPr');
1914
1915            // a:bodyPr
1916            $objWriter->writeElement('a:bodyPr', null);
1917
1918            // a:lstStyle
1919            $objWriter->writeElement('a:lstStyle', null);
1920
1921            // a:p
1922            $objWriter->startElement('a:p');
1923
1924            // a:pPr
1925            $objWriter->startElement('a:pPr');
1926
1927            // a:defRPr
1928            $objWriter->startElement('a:defRPr');
1929
1930            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1931            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1932            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1933            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1934            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1935            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000');
1936            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000');
1937
1938            // Font - a:solidFill
1939            $objWriter->startElement('a:solidFill');
1940
1941            $this->writeColor($objWriter, $series->getFont()->getColor());
1942
1943            $objWriter->endElement();
1944
1945            // Font - a:latin
1946            $objWriter->startElement('a:latin');
1947            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1948            $objWriter->endElement();
1949
1950            $objWriter->endElement();
1951
1952            $objWriter->endElement();
1953
1954            // a:endParaRPr
1955            $objWriter->startElement('a:endParaRPr');
1956            $objWriter->writeAttribute('lang', 'en-US');
1957            $objWriter->writeAttribute('dirty', '0');
1958            $objWriter->endElement();
1959
1960            $objWriter->endElement();
1961
1962            $objWriter->endElement();
1963
1964            // c:showLegendKey
1965            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1966
1967            // c:showVal
1968            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1969
1970            // c:showCatName
1971            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1972
1973            // c:showSerName
1974            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1975
1976            // c:showPercent
1977            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1978
1979            // c:showLeaderLines
1980            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1981
1982            $objWriter->endElement();
1983
1984            // c:spPr
1985            $objWriter->startElement('c:spPr');
1986            // Write fill
1987            $this->writeFill($objWriter, $series->getFill());
1988            // Write outline
1989            $this->writeOutline($objWriter, $series->getOutline());
1990            // ## c:spPr
1991            $objWriter->endElement();
1992
1993            // Write X axis data
1994            $axisXData = array_keys($series->getValues());
1995
1996            // c:cat
1997            $objWriter->startElement('c:cat');
1998            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1999            $objWriter->endElement();
2000
2001            // Write Y axis data
2002            $axisYData = array_values($series->getValues());
2003
2004            // c:val
2005            $objWriter->startElement('c:val');
2006            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
2007            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2008            $objWriter->endElement();
2009
2010            // c:smooth
2011            $objWriter->startElement('c:smooth');
2012            $objWriter->writeAttribute('val', '0');
2013            $objWriter->endElement();
2014
2015            $objWriter->endElement();
2016
2017            ++$seriesIndex;
2018        }
2019
2020        // c:axId
2021        $objWriter->startElement('c:axId');
2022        $objWriter->writeAttribute('val', '52743552');
2023        $objWriter->endElement();
2024
2025        // c:axId
2026        $objWriter->startElement('c:axId');
2027        $objWriter->writeAttribute('val', '52749440');
2028        $objWriter->endElement();
2029
2030        $objWriter->endElement();
2031    }
2032
2033    /**
2034     * Write Type Scatter
2035     *
2036     * @throws \Exception
2037     */
2038    protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void
2039    {
2040        // c:scatterChart
2041        $objWriter->startElement('c:scatterChart');
2042
2043        // c:scatterStyle
2044        $objWriter->startElement('c:scatterStyle');
2045        $objWriter->writeAttribute('val', 'lineMarker');
2046        $objWriter->endElement();
2047
2048        // c:varyColors
2049        $objWriter->startElement('c:varyColors');
2050        $objWriter->writeAttribute('val', '0');
2051        $objWriter->endElement();
2052
2053        // Write series
2054        $seriesIndex = 0;
2055        foreach ($subject->getSeries() as $series) {
2056            // c:ser
2057            $objWriter->startElement('c:ser');
2058
2059            // c:idx
2060            $objWriter->startElement('c:idx');
2061            $objWriter->writeAttribute('val', $seriesIndex);
2062            $objWriter->endElement();
2063
2064            // c:order
2065            $objWriter->startElement('c:order');
2066            $objWriter->writeAttribute('val', $seriesIndex);
2067            $objWriter->endElement();
2068
2069            // c:tx
2070            $objWriter->startElement('c:tx');
2071            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
2072            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
2073            $objWriter->endElement();
2074
2075            // c:spPr
2076            $objWriter->startElement('c:spPr');
2077            // Write fill
2078            $this->writeFill($objWriter, $series->getFill());
2079            // Write outline
2080            $this->writeOutline($objWriter, $series->getOutline());
2081            // ## c:spPr
2082            $objWriter->endElement();
2083
2084            // Marker
2085            $this->writeSeriesMarker($objWriter, $series->getMarker());
2086
2087            // c:dLbls
2088            $objWriter->startElement('c:dLbls');
2089
2090            // c:txPr
2091            $objWriter->startElement('c:txPr');
2092
2093            // a:bodyPr
2094            $objWriter->writeElement('a:bodyPr', null);
2095
2096            // a:lstStyle
2097            $objWriter->writeElement('a:lstStyle', null);
2098
2099            // a:p
2100            $objWriter->startElement('a:p');
2101
2102            // a:pPr
2103            $objWriter->startElement('a:pPr');
2104
2105            // a:defRPr
2106            $objWriter->startElement('a:defRPr');
2107
2108            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
2109            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
2110            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2111            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
2112            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
2113            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
2114            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
2115
2116            // Font - a:solidFill
2117            $objWriter->startElement('a:solidFill');
2118
2119            $this->writeColor($objWriter, $series->getFont()->getColor());
2120
2121            $objWriter->endElement();
2122
2123            // Font - a:latin
2124            $objWriter->startElement('a:latin');
2125            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2126            $objWriter->endElement();
2127
2128            $objWriter->endElement();
2129
2130            $objWriter->endElement();
2131
2132            // a:endParaRPr
2133            $objWriter->startElement('a:endParaRPr');
2134            $objWriter->writeAttribute('lang', 'en-US');
2135            $objWriter->writeAttribute('dirty', '0');
2136            $objWriter->endElement();
2137
2138            $objWriter->endElement();
2139
2140            $objWriter->endElement();
2141
2142            // c:showLegendKey
2143            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
2144
2145            // c:showVal
2146            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
2147
2148            // c:showCatName
2149            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
2150
2151            // c:showSerName
2152            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
2153
2154            // c:showPercent
2155            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2156
2157            // c:separator
2158            $separator = $series->getSeparator();
2159            if (!empty($separator) && PHP_EOL != $separator) {
2160                // c:dLbls\c:separator
2161                $objWriter->writeElement('c:separator', $separator);
2162            }
2163
2164            // c:showLeaderLines
2165            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2166
2167            $objWriter->endElement();
2168
2169            // Write X axis data
2170            $axisXData = array_keys($series->getValues());
2171
2172            // c:xVal
2173            $objWriter->startElement('c:xVal');
2174            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2175            $objWriter->endElement();
2176
2177            // Write Y axis data
2178            $axisYData = array_values($series->getValues());
2179
2180            // c:yVal
2181            $objWriter->startElement('c:yVal');
2182            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
2183            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2184            $objWriter->endElement();
2185
2186            // c:smooth
2187            $objWriter->startElement('c:smooth');
2188            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
2189            $objWriter->endElement();
2190
2191            $objWriter->endElement();
2192
2193            ++$seriesIndex;
2194        }
2195
2196        // c:axId
2197        $objWriter->startElement('c:axId');
2198        $objWriter->writeAttribute('val', '52743552');
2199        $objWriter->endElement();
2200
2201        // c:axId
2202        $objWriter->startElement('c:axId');
2203        $objWriter->writeAttribute('val', '52749440');
2204        $objWriter->endElement();
2205
2206        $objWriter->endElement();
2207    }
2208
2209    /**
2210     * Write chart relationships to XML format.
2211     *
2212     * @return string XML Output
2213     *
2214     * @throws \Exception
2215     */
2216    public function writeChartRelationships(Chart $pChart): string
2217    {
2218        // Create XML writer
2219        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
2220
2221        // XML header
2222        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
2223
2224        // Relationships
2225        $objWriter->startElement('Relationships');
2226        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
2227
2228        // Write spreadsheet relationship?
2229        if ($pChart->hasIncludedSpreadsheet()) {
2230            $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/package', '../embeddings/' . $pChart->getIndexedFilename() . '.xlsx');
2231        }
2232
2233        $objWriter->endElement();
2234
2235        // Return
2236        return $objWriter->getData();
2237    }
2238
2239    protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void
2240    {
2241        // c:marker
2242        $objWriter->startElement('c:marker');
2243        // c:marker > c:symbol
2244        $objWriter->startElement('c:symbol');
2245        $objWriter->writeAttribute('val', $marker->getSymbol());
2246        $objWriter->endElement();
2247
2248        // Size if different of none
2249        if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) {
2250            $markerSize = (int) $marker->getSize();
2251            if ($markerSize < 2) {
2252                $markerSize = 2;
2253            }
2254            if ($markerSize > 72) {
2255                $markerSize = 72;
2256            }
2257
2258            /*
2259             * c:marker > c:size
2260             * Size in points
2261             * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx
2262             */
2263            $objWriter->startElement('c:size');
2264            $objWriter->writeAttribute('val', $markerSize);
2265            $objWriter->endElement();
2266        }
2267
2268        // // c:marker > c:spPr
2269        $objWriter->startElement('c:spPr');
2270        $this->writeFill($objWriter, $marker->getFill());
2271        $this->writeBorder($objWriter, $marker->getBorder(), '', true);
2272        $objWriter->endElement();
2273
2274        // > c:marker
2275        $objWriter->endElement();
2276    }
2277
2278    /**
2279     * @throws \Exception
2280     */
2281    protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void
2282    {
2283        if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) {
2284            return;
2285        }
2286
2287        if (Chart\Axis::AXIS_X == $typeAxis) {
2288            $mainElement = 'c:catAx';
2289            $axIdVal = '52743552';
2290            $axPosVal = 'b';
2291            $crossAxVal = '52749440';
2292        } else {
2293            $mainElement = 'c:valAx';
2294            $axIdVal = '52749440';
2295            $axPosVal = 'l';
2296            $crossAxVal = '52743552';
2297        }
2298
2299        // $mainElement
2300        $objWriter->startElement($mainElement);
2301
2302        // $mainElement > c:axId
2303        $objWriter->startElement('c:axId');
2304        $objWriter->writeAttribute('val', $axIdVal);
2305        $objWriter->endElement();
2306
2307        // $mainElement > c:scaling
2308        $objWriter->startElement('c:scaling');
2309
2310        // $mainElement > c:scaling > c:orientation
2311        $objWriter->startElement('c:orientation');
2312        $objWriter->writeAttribute('val', 'minMax');
2313        $objWriter->endElement();
2314
2315        if (null != $oAxis->getMaxBounds()) {
2316            $objWriter->startElement('c:max');
2317            $objWriter->writeAttribute('val', $oAxis->getMaxBounds());
2318            $objWriter->endElement();
2319        }
2320
2321        if (null != $oAxis->getMinBounds()) {
2322            $objWriter->startElement('c:min');
2323            $objWriter->writeAttribute('val', $oAxis->getMinBounds());
2324            $objWriter->endElement();
2325        }
2326
2327        // $mainElement > ##c:scaling
2328        $objWriter->endElement();
2329
2330        // $mainElement > c:delete
2331        $objWriter->startElement('c:delete');
2332        $objWriter->writeAttribute('val', $oAxis->isVisible() ? '0' : '1');
2333        $objWriter->endElement();
2334
2335        // $mainElement > c:axPos
2336        $objWriter->startElement('c:axPos');
2337        $objWriter->writeAttribute('val', $axPosVal);
2338        $objWriter->endElement();
2339
2340        $oMajorGridlines = $oAxis->getMajorGridlines();
2341        if ($oMajorGridlines instanceof Gridlines) {
2342            $objWriter->startElement('c:majorGridlines');
2343
2344            $this->writeAxisGridlines($objWriter, $oMajorGridlines);
2345
2346            $objWriter->endElement();
2347        }
2348
2349        $oMinorGridlines = $oAxis->getMinorGridlines();
2350        if ($oMinorGridlines instanceof Gridlines) {
2351            $objWriter->startElement('c:minorGridlines');
2352
2353            $this->writeAxisGridlines($objWriter, $oMinorGridlines);
2354
2355            $objWriter->endElement();
2356        }
2357
2358        if ('' != $oAxis->getTitle()) {
2359            // c:title
2360            $objWriter->startElement('c:title');
2361
2362            // c:tx
2363            $objWriter->startElement('c:tx');
2364
2365            // c:rich
2366            $objWriter->startElement('c:rich');
2367
2368            // a:bodyPr
2369            $objWriter->startElement('a:bodyPr');
2370            $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle($oAxis->getTitleRotation()));
2371            $objWriter->endElement();
2372
2373            // a:lstStyle
2374            $objWriter->writeElement('a:lstStyle', null);
2375
2376            // a:p
2377            $objWriter->startElement('a:p');
2378
2379            // a:pPr
2380            $objWriter->startElement('a:pPr');
2381
2382            // a:defRPr
2383            $objWriter->startElement('a:defRPr');
2384
2385            $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false'));
2386            $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false'));
2387            $objWriter->writeAttribute('strike', ($oAxis->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2388            $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100));
2389            $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline());
2390            $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '300000');
2391            $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-250000');
2392
2393            // Font - a:solidFill
2394            $objWriter->startElement('a:solidFill');
2395            $this->writeColor($objWriter, $oAxis->getFont()->getColor());
2396            $objWriter->endElement();
2397
2398            // Font - a:latin
2399            $objWriter->startElement('a:latin');
2400            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2401            $objWriter->endElement();
2402
2403            $objWriter->endElement();
2404
2405            // ## a:pPr
2406            $objWriter->endElement();
2407
2408            // a:r
2409            $objWriter->startElement('a:r');
2410
2411            // a:rPr
2412            $objWriter->startElement('a:rPr');
2413            $objWriter->writeAttribute('lang', 'en-US');
2414            $objWriter->writeAttribute('dirty', '0');
2415            $objWriter->endElement();
2416
2417            // a:t
2418            $objWriter->writeElement('a:t', $oAxis->getTitle());
2419
2420            // ## a:r
2421            $objWriter->endElement();
2422
2423            // a:endParaRPr
2424            $objWriter->startElement('a:endParaRPr');
2425            $objWriter->writeAttribute('lang', 'en-US');
2426            $objWriter->writeAttribute('dirty', '0');
2427            $objWriter->endElement();
2428
2429            // ## a:p
2430            $objWriter->endElement();
2431
2432            // ## c:rich
2433            $objWriter->endElement();
2434
2435            // ## c:tx
2436            $objWriter->endElement();
2437
2438            // ## c:title
2439            $objWriter->endElement();
2440        }
2441
2442        // c:numFmt
2443        $objWriter->startElement('c:numFmt');
2444        $objWriter->writeAttribute('formatCode', $oAxis->getFormatCode());
2445        $objWriter->writeAttribute('sourceLinked', '1');
2446        $objWriter->endElement();
2447
2448        // c:majorTickMark
2449        $objWriter->startElement('c:majorTickMark');
2450        $objWriter->writeAttribute('val', $oAxis->getMajorTickMark());
2451        $objWriter->endElement();
2452
2453        // c:minorTickMark
2454        $objWriter->startElement('c:minorTickMark');
2455        $objWriter->writeAttribute('val', $oAxis->getMinorTickMark());
2456        $objWriter->endElement();
2457
2458        // c:tickLblPos
2459        $objWriter->startElement('c:tickLblPos');
2460        $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition());
2461        $objWriter->endElement();
2462
2463        // c:spPr
2464        $objWriter->startElement('c:spPr');
2465        // Outline
2466        $this->writeOutline($objWriter, $oAxis->getOutline());
2467        // ##c:spPr
2468        $objWriter->endElement();
2469
2470        // c:crossAx
2471        $objWriter->startElement('c:crossAx');
2472        $objWriter->writeAttribute('val', $crossAxVal);
2473        $objWriter->endElement();
2474
2475        // c:crosses
2476        $objWriter->startElement('c:crosses');
2477        $objWriter->writeAttribute('val', 'autoZero');
2478        $objWriter->endElement();
2479
2480        if (Chart\Axis::AXIS_X == $typeAxis) {
2481            // c:lblAlgn
2482            $objWriter->startElement('c:lblAlgn');
2483            $objWriter->writeAttribute('val', 'ctr');
2484            $objWriter->endElement();
2485
2486            // c:lblOffset
2487            $objWriter->startElement('c:lblOffset');
2488            $objWriter->writeAttribute('val', '100');
2489            $objWriter->endElement();
2490
2491            // c:majorUnit
2492            if ($oAxis->getMajorUnit() != null) {
2493                $objWriter->startElement('c:tickLblSkip');
2494                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2495                $objWriter->endElement();
2496            }
2497        }
2498
2499        if (Chart\Axis::AXIS_Y == $typeAxis) {
2500            // c:crossBetween
2501            $objWriter->startElement('c:crossBetween');
2502            // midCat : Position Axis On Tick Marks
2503            // between : Between Tick Marks
2504            if ($typeChart instanceof Area) {
2505                $objWriter->writeAttribute('val', 'midCat');
2506            } else {
2507                $objWriter->writeAttribute('val', 'between');
2508            }
2509            $objWriter->endElement();
2510
2511            // c:majorUnit
2512            if (null != $oAxis->getMajorUnit()) {
2513                $objWriter->startElement('c:majorUnit');
2514                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2515                $objWriter->endElement();
2516            }
2517
2518            // c:minorUnit
2519            if (null != $oAxis->getMinorUnit()) {
2520                $objWriter->startElement('c:minorUnit');
2521                $objWriter->writeAttribute('val', $oAxis->getMinorUnit());
2522                $objWriter->endElement();
2523            }
2524        }
2525
2526        $objWriter->endElement();
2527    }
2528
2529    /**
2530     * @throws \Exception
2531     */
2532    protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void
2533    {
2534        // c:spPr
2535        $objWriter->startElement('c:spPr');
2536
2537        // Outline
2538        $this->writeOutline($objWriter, $oGridlines->getOutline());
2539
2540        // ##c:spPr
2541        $objWriter->endElement();
2542    }
2543}